/**
 * 维护群监控加人业务
 *
 * 业务实体关系：
 * - MonitorConfig     一项监控配置：指定要监控的若干“企业微信”，及监控条件
 *    - MonitorTask    监控配置启用后，会为其中每个企业微信开启一个 task，即监控任务
 *      - ApplyRecord  企业微信的加人记录
 */
import { Service } from '@gnlab/utils'
import type { Dayjs } from 'dayjs'
import { makeHTTPSAvatar } from '@/lib/https'
import { toISOString } from '@/lib/utils'
import type { Services } from '@/services'
import { API } from '@/services/common/api'
import { friendlyQywxName } from '@/services/qywxs'

// 可监控的群类型
export enum MonitorGroupType {
  CorpExternal = 1, // 企业微信自己公司的“外部群”
  External = 2, // 其他公司的“外部群”（即我们的企业微信是以外部成员的身份进群的）
}

// 添加好友的验证消息中可用的变量
export enum ApplyMessageVar {
  QywxName = 'WxWorkName', // 自己的微信昵称
  MemberName = 'WxName', // 目标好友的名称
  GroupName = 'RoomName', // 群名称
}

export interface BaseMonitorConfig {
  name: string // 名称
  enable: boolean // 是否已启用
  wxids: string[] // 此配置包含哪些企业微信
  types: MonitorGroupType[] // 监控哪些类型的群
  ignoreApplyedByOther: boolean // 是否忽略已被其他企微添加过好友的联系人
  ignoreApplyed: boolean // 是否忽略过去 N 天内发送过好友申请的人
  ignoreApplyedDays: number // 仅 ignoreApplyed 为 true 时有效，忽略多少天内发送过请求的人
  dailyLimit: number // 每天加好友的上限
  applyMessage: string // 加好友时的验证消息
}

export interface MonitorConfig extends BaseMonitorConfig {
  id: number // ID
  applyedCount: number // 已发送请求数
  passedCount: number // 已通过请求数
}

interface RawBaseMonitorConfig {
  Name: string
  Enable: boolean
  WxIds: string[]
  IsMyCorp: boolean
  IsNotMyCorp: boolean
  IsOtherWxContact: boolean
  IsApplyed: boolean
  ApplyedDays: number
  PerDayCount: number
  ApplyMessage: string
}

interface RawMonitorConfig extends RawBaseMonitorConfig {
  Id: number
  ApplyCount: number
  PassCount: number
}

function formatMonitorConfig(raw: RawMonitorConfig): MonitorConfig {
  return {
    id: raw.Id,
    name: raw.Name,
    enable: raw.Enable,
    wxids: raw.WxIds,
    types: [
      raw.IsMyCorp ? MonitorGroupType.CorpExternal : null,
      raw.IsNotMyCorp ? MonitorGroupType.External : null,
    ].filter(v => v !== null) as MonitorGroupType[],
    ignoreApplyedByOther: raw.IsOtherWxContact,
    ignoreApplyed: raw.IsApplyed,
    ignoreApplyedDays: raw.ApplyedDays,
    dailyLimit: raw.PerDayCount,
    applyMessage: raw.ApplyMessage,
    applyedCount: raw.ApplyCount,
    passedCount: raw.PassCount,
  }
}

export function makeRawMonitorConfig(config: BaseMonitorConfig): RawBaseMonitorConfig {
  return {
    Name: config.name,
    Enable: config.enable,
    WxIds: config.wxids,
    IsMyCorp: config.types.includes(MonitorGroupType.CorpExternal),
    IsNotMyCorp: config.types.includes(MonitorGroupType.External),
    IsOtherWxContact: config.ignoreApplyedByOther,
    IsApplyed: config.ignoreApplyed,
    ApplyedDays: config.ignoreApplyedDays,
    PerDayCount: config.dailyLimit,
    ApplyMessage: config.applyMessage,
  }
}

export function getEmptyMonitorConfig(): BaseMonitorConfig {
  return {
    name: '',
    enable: false,
    wxids: [],
    types: [],
    ignoreApplyedByOther: false,
    ignoreApplyed: false,
    ignoreApplyedDays: 7,
    dailyLimit: 500,
    applyMessage: '',
  }
}

// 监控配置涉及的企业微信信息
export interface MonitorConfigQywx {
  wxid: string
  username: string
  nickname: string
  corpname: string
  friendlyName: string
  friendlyFullName: string
  avatar: string
  accountName: string
  accountRemark: string
  configId?: number | null // number: 此企业微信被加入了哪个监控配置，为 null 代表还没有被加入配置
}

interface RawMonitorConfigQywx {
  NickName: string
  UserName: string
  CorpName: string
  Avatar: string
  UserAccountName: string
  UserAccountRemarkName: string | null
  WxId: string
  ConfigId: number
}

function formatMonitorConfigQywx(raw: RawMonitorConfigQywx): MonitorConfigQywx {
  const base = {
    wxid: raw.WxId,
    username: raw.UserName,
    nickname: raw.NickName,
    corpname: raw.CorpName,
    avatar: makeHTTPSAvatar(raw.Avatar),
    accountName: raw.UserAccountName,
    accountRemark: raw.UserAccountRemarkName ?? '',
    configId: raw.ConfigId === 0 ? null : raw.ConfigId,
  }
  return {
    ...base,
    friendlyName: friendlyQywxName(base, false),
    friendlyFullName: friendlyQywxName(base),
  }
}

export enum MonitorTaskStatus {
  Normal = 0, // 正常
  Exceed = 1, // 过频停止（企业微信方限制）
  Limited = 2, // 到达设置上限（用户自己的设置）
}

export interface MonitorTask {
  id: number // 企业微信加人任务 id
  wxid: string // 企业微信 id
  status: MonitorTaskStatus // 任务状态
  applyedCount: number // 发送申请的数量
  passedCount: number // 申请通过的数量
}

interface RawMonitorTask {
  Id: number
  WxId: string
  Status: MonitorTaskStatus
  ApplyCount: number
  PassCount: number
}

function formatMonitiorTask(raw: RawMonitorTask): MonitorTask {
  return {
    id: raw.Id,
    status: raw.Status,
    applyedCount: raw.ApplyCount,
    passedCount: raw.PassCount,
    wxid: raw.WxId,
  }
}

// 添加好友状态
export enum ApplyStatus {
  Applyed = 0, // 已申请（尚未通过）
  Passed = 1, // 已通过好友请求
}

export interface MonitorApplyRecord {
  groupName: string // 此好友来自哪个群
  groupJoined: Date // 此好友进群时间
  applyPassed: Date | null // 申请通过时间
  contactName: string // 好友昵称
  status: ApplyStatus // 添加状态
}

interface RawMonitorApplyRecord {
  ContactUserName: string
  RoomName: string
  CreateTime: string
  PassTime: string | null
  State: ApplyStatus
}

function formatMonitorApplyRecord(raw: RawMonitorApplyRecord): MonitorApplyRecord {
  return {
    groupName: raw.RoomName,
    groupJoined: new Date(raw.CreateTime),
    applyPassed: raw.PassTime !== null ? new Date(raw.PassTime) : null,
    contactName: raw.ContactUserName,
    status: raw.State,
  }
}

export class GroupMonitorApply extends Service<Services> {
  /**
   * 获取用于监控配置的企业微信列表
   *
   * 若指定 configId，则返回所有在线企业微信，以及处于这个 config 中但是不在线的企业微信
   * 若不指定 configId，则仅返回所有在线企业微信
   */
  async getQywxListForConfig(configId?: number) {
    return API('/RoomAddMember/GetRoomAddMemberWxUserList', {
      data: { ConfigId: configId },
      formatter(raw: RawMonitorConfigQywx[]) {
        return raw.map(formatMonitorConfigQywx)
      },
    })
  }

  async loadConfigs() {
    return API('/RoomAddMember/GetRoomAddMemberConfigs', {
      formatter(list: RawMonitorConfig[]) {
        return list.map(formatMonitorConfig)
      },
    })
  }

  async addOrUpdateConfig(data: BaseMonitorConfig & { id?: number }) {
    return API('/RoomAddMember/SaveRoomAddMemberConfig', {
      data: {
        Id: data.id,
        ...makeRawMonitorConfig(data),
      },
      formatter() {},
    })
  }

  async removeConfig(id: number) {
    return API('/RoomAddMember/RemoveRoomAddMemberConfig', {
      data: { Id: id },
      formatter() {},
    })
  }

  async loadTasks(configId: number, time?: [Dayjs, Dayjs]) {
    return API('/RoomAddMember/GetRoomAddMemberTasks', {
      data: {
        ConfigId: configId,
        BeginTime: time ? toISOString(time[0]) : undefined,
        EndTime: time ? toISOString(time[1]) : undefined,
      },
      formatter(raw: RawMonitorTask[]) {
        return raw.map(formatMonitiorTask)
      },
    })
  }

  async loadApplyRecords(taskId: number) {
    return API('/RoomAddMember/GetRoomAddMemberRecords', {
      data: { TaskId: taskId },
      formatter(raw: RawMonitorApplyRecord[]) {
        return raw.map(formatMonitorApplyRecord)
      },
    })
  }
}
